/*
 * Copyright (c) 2014 Strong Group - 版权所有
 * 
 * This software is the confidential and proprietary information of
 * Strong Group. You shall not disclose such confidential information 
 * and shall use it only in accordance with the terms of the license 
 * agreement you entered into with www.cnstrong.cn.
 */
package com.zuorenke.serialize.support.json;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.zuorenke.serialize.ObjectInput;
import com.zuorenke.serialize.Serialization;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

public class JsonUtils {
	private JsonUtils(){}
	public static final String JSON_DESERIAL_ERROR = "Json deserial error.";
	private static final Serialization serialization = new JacksonSerialization();

	private static ObjectMapper mapper = null;

	static {
		if (mapper == null) {
			mapper = new ObjectMapper(new JsonFactory());
			mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
			mapper.setTimeZone(TimeZone.getDefault());
		}
	}

	/**
	 * Object to JSON.
	 * @param object
	 * @return
	 */
	public static String toJson(Object object) {
		if (object == null) {
			return null;
		}
		try {
			return mapper.writeValueAsString(object);
		} catch (Exception e) {
			throw new JsonException("Json serial error.", e);
		}
	}

	/**
	 * JSON to Object.
	 * @param json
	 * @param valueType
	 * @return
	 */
	public static <T> T fromJson(String json, JavaType valueType) {
		if (json == null) {
			return null;
		}
		try {
			return mapper.readValue(json, valueType);
		} catch (Exception e) {
			throw new JsonException(JSON_DESERIAL_ERROR, e);
		}
	}
	
	public static <T> List<T> fromJsonToList(String json, TypeReference<List<T>> typeReference){
		try {
			return mapper.readValue(json, typeReference);
		} catch (IOException e) {
			throw new JsonException(JSON_DESERIAL_ERROR, e);
		}
	}

	/**
	 * JSON to Object.
	 * @param json
	 * @param clazz
	 * @return
	 */
	public static final <T> T fromJson(String json, Class<T> clazz) {
		return fromJson(json, getTypeFactory().constructType(clazz));
	}

	public static <T> T fromJson(InputStream input, JavaType valueType) {
		try {
			return mapper.readValue(input, valueType);
		} catch (Exception e) {
			throw new JsonException(JSON_DESERIAL_ERROR, e);
		}
	}

	public static final <T> T fromJson(InputStream input, Class<T> clazz) {
		try {
			return mapper.readValue(input, clazz);
		} catch (Exception e) {
			throw new JsonException(JSON_DESERIAL_ERROR, e);
		}
	}

	/**
	 * JSON to Array.
	 * @param json
	 * @param clazz
	 * @return
	 */
	public static final <T> T[] readArray(String json, Class<T> clazz) {
		return fromJson(json, getTypeFactory().constructArrayType(clazz));
	}

	/**
	 * JSON to List.
	 * @param json
	 * @param clazz
	 * @return
	 */
	public static final <T> List<T> readList(String json, Class<T> clazz) {
		return fromJson(json, getTypeFactory().constructCollectionType(ArrayList.class, clazz));
	}

	public static final <T> List<T> readList(InputStream input, Class<T> clazz) {
		return fromJson(input, getTypeFactory().constructCollectionType(ArrayList.class, clazz));
	}

	/**
	 * JSON to Map.
	 * @param json
	 * @param keyClazz
	 * @param valueClazz
	 * @return
	 */
	public static final <K, V> Map<K, V> readMap(String json, Class<K> keyClazz, Class<V> valueClazz) {
		return fromJson(json, getTypeFactory().constructMapType(HashMap.class, keyClazz, valueClazz));
	}

	public static final TypeFactory getTypeFactory() {
		return mapper.getTypeFactory();
	}

}
